#pragma once

#include"Sem.hpp"
#include"Mutex.hpp"
#include<vector>

static const int gcap = 5; // for debug

using namespace SemModule;
using namespace MutexModule;

template<typename T>
class RingQueue
{
    public:
        RingQueue(int cap = gcap)
            :_cap(cap),
            _rq(cap),
            _blank_sem(cap),
            _p_step(0),
            _data_sem(0),
            _c_step(0)
        {
        }
        void Equeue(const T &in)
        {
            //生产者
            //申请信号量，申请空位置信号量
            _blank_sem.P();
            {
                LockGuard lockguar(_pmutex);
                //生产
                _rq[_p_step] = in;
                //更新下标
                ++_p_step;
                //维持环形特性
                _p_step %= _cap;
            }
            _blank_sem.V();
        }
        void Pop(T *out)
        {
            //消费者
            //申请信号量，数据信号量
            _data_sem.P();
            {
                LockGuard lockguard(_cmutex);
                //消费
                *out = _rq[_c_step];
                //更新下标
                ++_c_step;
                //维持环特性
                _c_step %= _cap;
            }
            _blank_sem.V();
        }

    private:
        std::vector<T> _rq;
        int _cap;
        
        //生产者
        Sem _blank_sem;//空位置
        int _p_step;
        //消费者
        Sem _data_sem;//数据
        int _c_step;

        //维护多生产、多消费 俩把锁
        Mutex _cmutex;
        Mutex _pmutex;

};
